package com.luca.sl651server.server.codec;

import com.luca.sl651server.constant.FrameConstant;
import com.luca.sl651server.dto.req.FrameReqHeader;
import com.luca.sl651server.dto.req.FrameReqWrapper;
import com.luca.sl651server.enums.FrameFuncCodeEnum;
import com.luca.sl651server.enums.ServiceCodeEnum;
import com.luca.sl651server.util.FrameUtil;
import com.luca.sl651server.util.HexStringUtil;
import com.luca.sl651server.dto.req.FrameReq;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.List;

public class NettyFrameDecoder extends ByteToMessageDecoder {
    private static final Logger LOGGER = LoggerFactory.getLogger(NettyFrameDecoder.class);
    private boolean crcVerifyFlag = false;
    private FrameHeaderDecoder headerDecoder;
    private FrameBodyDecoder bodyDecoder;

    public NettyFrameDecoder(boolean crcVerifyFlag, FrameHeaderDecoder headerDecoder, FrameBodyDecoder bodyDecoder) {
        this.crcVerifyFlag = crcVerifyFlag;
        this.headerDecoder = headerDecoder;
        this.bodyDecoder = bodyDecoder;
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list)
            throws Exception {
        FrameReqWrapper wrapper = this.decodeFrame(byteBuf);
        list.add(wrapper);
    }

    public FrameReqWrapper decodeFrame(ByteBuf byteBuf) {
        FrameReqWrapper wrapper = new FrameReqWrapper();
        try {
            String frameHexStr = ByteBufUtil.hexDump(byteBuf);
            LOGGER.info("sl651-2014 frame hex content>>>" + frameHexStr);
            wrapper = decodeHex(frameHexStr);
            FrameReq frameReq = wrapper.getReqDto();
            LOGGER.info("[收到水位数据]sl651-2014 remoteStationAddr:{}, 标识符：{}，  解析后的数据 content>>> {}", frameReq.getHeader().getRemoteStationAddr(), frameReq.toString());
            return wrapper;
        } catch (Exception e) {
            LOGGER.error("[水位数据解析出错] sl651-2014 frame decode error", e);
            wrapper.setWrapCodeEnum(ServiceCodeEnum.SERVICE_ERROR);
        } finally {
            byteBuf.skipBytes(byteBuf.readableBytes());
        }
        return wrapper;
    }

    public FrameReqWrapper decodeHex(String frameHexStr) {
        FrameReqWrapper wrapper = new FrameReqWrapper();
        FrameReq frameReq = new FrameReq();
        wrapper.setReqDto(frameReq);

        wrapper.setOriginalFrame(frameHexStr);
        char[] frame = HexStringUtil.hexStr2CharArray(frameHexStr);
        if (crcVerifyFlag && !FrameUtil.verifyCRC16Code(frame)) {
            LOGGER.warn("sl651-2014 frame crc verify fail>>>" + frameHexStr);
            wrapper.setWrapCodeEnum(ServiceCodeEnum.SERVICE_CRC_VERIFY_FAIL);
            return wrapper;
        }
        FrameReqHeader header = headerDecoder.decodeHeader(frame);
        frameReq.setHeader(header);
        int bodyLen = header.getBodyLen().intValue();
        if (header.isM3Mode()) {
            frameReq.setBody(bodyDecoder.decodeM3Body(FrameUtil.getM3Body(frame, bodyLen)));
        } else {
            frameReq.setBody(bodyDecoder.decodeM124Body(FrameUtil.getM124Body(frame, bodyLen),
                    FrameFuncCodeEnum.getFrameFuncEnum(header.getFuncCode())));
        }
        frameReq.setBodyEndSymbol(FrameUtil.getBodyEndSymbol(frame));
        frameReq.setCrcCode(FrameUtil.getCRC16Code(frame));
        wrapper.setWrapCodeEnum(ServiceCodeEnum.SERVICE_SUCCESS);
        return wrapper;
    }

    public static void main(String[] args) throws Exception {
        String data =
                "7e7e0100660166010451330021020143060509154033f1f1006601660148f0f006050915403923000350003812129403179d";
//              "7e7e0100660166010451330021020038241216180532f1f1006601660148f0f02412161805392300035000381212970327ba";
//                "7E7E010010100001A00032002B02000C200724172349F1F1001010000148F0F020072417232019000130221900004039230000055038121268038397";
//                "7e7e010011111112000032002b02002b200321153057f1f1001111111248f0f020032115303922000098362019000000261900000038122400037b54";
        ByteBuf buffer = Unpooled.copiedBuffer(Hex.decodeHex(data));
        System.out.println(ByteBufUtil.hexDump(buffer));

        NettyFrameDecoder decoder =
                new NettyFrameDecoder(false, new FrameHeaderDecoderImpl(), new FrameBodyDecoderImpl());
        FrameReqWrapper wrapper = decoder.decodeFrame(buffer);
        System.out.println(
                wrapper.getReqDto().getBody().getElementMap().get(FrameConstant.BODY_ELEMENT_REVIER).get(0).getVal());
        SimpleDateFormat sd = new SimpleDateFormat("yyyyMMddHHmm");
        System.out.println(sd.parse(wrapper.getReqDto().getBody().getObserveTime()));
    }
}
